package com.sky.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.mapper.AddressBookMapper;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ShoppingCartMapper;
import com.sky.result.PageBean;
import com.sky.service.OrderService;
import com.sky.service.ShoppingCartService;
import com.sky.socket.WebSocketServer;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private ShoppingCartService shoppingCartService;

    @Autowired
    private WebSocketServer webSocketServer;


    /**
     * 用户提交订单
     *
     * @param dto 用户的请求参数dto
     * @return 订单信息
     */
    @Override
    @Transactional
    public OrderSubmitVO submitOrder(OrdersSubmitDTO dto) {
        // 往数据库添加数据
        // 1.准备数据(下单用户,地址信息,购物车中的商品信息)
        Long userId = BaseContext.getCurrentId();
        // 根据地址簿id查询地址信息
        AddressBook addressBook = addressBookMapper.selectById(dto.getAddressBookId());
        // 查询出该用户购物车中的所有商品(用户id)
        List<ShoppingCart> list = shoppingCartMapper.list(ShoppingCart.builder().userId(userId).build());

        // 2.添加订单数据(1条)
        Orders orders = new OrderVO();
        BeanUtils.copyProperties(dto, orders);
        // 设置订单号(当前时间+用户id)
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        orders.setNumber(now.format(formatter) + userId);
        // 订单详细地址
        orders.setAddress(addressBook.getDetail());
        orders.setOrderTime(LocalDateTime.now());
        orders.setUserId(userId);
        // 支付状态 当前处于未支付
        orders.setPayStatus(Orders.UN_PAID);
        orders.setPhone(addressBook.getPhone());
        // 收货人
        orders.setConsignee(addressBook.getConsignee());
        // 订单状态 当前处于待支付
        orders.setStatus(Orders.PENDING_PAYMENT);

        orderMapper.insert(orders); // 插入订单数据后主键自增返回

        // 3.添加订单表详细数据(一个订单对应多个商品)
        List<OrderDetail> orderDetailList = list.stream().map(shoppingCart -> {
            OrderDetail orderDetail = new OrderDetail();
            // 将购物车中的每一条数据转换成订单详情
            BeanUtils.copyProperties(shoppingCart, orderDetail);
            // 订单数据详情的订单id
            orderDetail.setOrderId(orders.getId());
            return orderDetail;
        }).collect(Collectors.toList());

        // 向订单详情表中插入多条数据
        orderDetailMapper.insertBatch(orderDetailList);

        // 4.清空购物车
        shoppingCartMapper.delete(ShoppingCart.builder().userId(userId).build());

        return OrderSubmitVO.builder()
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .orderNumber(orders.getNumber())
                .id(orders.getId())
                .build();
    }

    /**
     * 历史订单查询
     *
     * @param dto dto
     * @return pageBean
     */
    @Override
    public PageBean queryingHistoryOrders(OrdersPageQueryDTO dto) {
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        dto.setUserId(BaseContext.getCurrentId());
        Page<OrderVO> orderVOS = orderDetailMapper.queryingHistoryOrders(dto);
//        for (OrderVO orderVO : orderVOS) {
//            orderVO.setOrderDetailList();
//        }
        return PageBean.builder()
                .total(orderVOS.getTotal())
                .records(orderVOS.getResult())
                .build();
    }

    /**
     * 查询订单详情
     *
     * @param id 订单id
     * @return orderVO
     */
    @Override
    public OrderVO selectWithDetailById(Long id) {
        OrderVO orderVO = orderMapper.selectWithDetailById(id);
        System.out.println("订单详情为: " + orderVO);
        return orderVO;
    }

    /**
     * 再来一单
     *
     * @param id 订单id
     */
    @Override
    @Transactional
    public void oneMoreOrder(Long id) {
        // 再来一单
        List<OrderDetail> orderDetailList = orderDetailMapper.selectByOrderId(id);
        for (OrderDetail orderDetail : orderDetailList) {
            ShoppingCart shoppingCart = ShoppingCart.builder()
                    .userId(BaseContext.getCurrentId())
                    .createTime(LocalDateTime.now())
                    .build();
            BeanUtils.copyProperties(orderDetail, shoppingCart);
            shoppingCartMapper.insert(shoppingCart);
        }
    }

    /**
     * 取消订单
     *
     * @param id 订单id
     */
    @Override
    @Transactional
    public void cancelOrder(Long id) {
        //  1. 校验订单是否存在
        //  2. 校验订单状态：仅待付款和待接单状态的订单可以直接取消，其他状态的不能取消
        //  3. 如果订单状态为待接单且支付状态为已支付的情况下，还需要进行退款操作
        OrderVO orderVO = orderMapper.selectWithDetailById(id);
        if (orderVO == null) return;

        if (orderVO.getStatus().equals(Orders.PENDING_PAYMENT)) {
            orderMapper.updateByOrderId(id, Orders.CANCELLED, null);
        }
        if ((orderVO.getStatus().equals(Orders.TO_BE_CONFIRMED))) {
            if (orderVO.getPayStatus().equals(Orders.UN_PAID)) {
                orderMapper.updateByOrderId(id, Orders.CANCELLED, Orders.REFUND);
            }
            orderMapper.updateByOrderId(id, Orders.CANCELLED, null);
        }
    }

    /**
     * 订单支付
     * 因为无法对接微信支付接口
     * 这里只是修改支付状态和订单状态
     *
     * @param dto dto
     * @return 预计送达时间
     */
    @Override
    public String payment(OrdersPaymentDTO dto) {
        Orders orders = orderMapper.selectByNumber(dto.getOrderNumber());
        // 订单状态 2待接单
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        // 支付状态 1已支付
        orders.setPayStatus(Orders.PAID);
        // 付款方式
        orders.setPayMethod(dto.getPayMethod());
        orderMapper.updateOrder(orders);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", 1);
        jsonObject.put("orderId", orders.getId());
        jsonObject.put("content", "订单号: " + orders.getNumber());
        webSocketServer.sendToAllClient(jsonObject.toString());
        return null;
    }

    /**
     * 订单搜索(管理端)
     *
     * @param dto dto
     * @return pageBean
     */
    @Override
    public PageBean selectOrders(OrdersPageQueryDTO dto) {
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        Page<OrderVO> orderVOS = orderMapper.selectOrders(dto);

        orderVOS.getResult().forEach(orderVO -> {
            StringJoiner sj = new StringJoiner(",");
            orderVO.getOrderDetailList().forEach(orderDetail -> {
                sj.add(orderDetail.getName() + "*" + orderDetail.getNumber());
            });
            orderVO.setOrderDishes(sj.toString());
        });

        for (OrderVO orderVO : orderVOS.getResult()) {
            System.out.println("订单详情: " + orderVO.getOrderDishes());
        }


        return PageBean.builder()
                .total(orderVOS.getTotal())
                .records(orderVOS.getResult())
                .build();
    }

    /**
     * 各个状态的订单数量统计
     *
     * @return 数量统计
     */
    @Override
    public OrderStatisticsVO selectOrderStatusQuantityStatistics() {
        return orderMapper.selectOrderStatusQuantityStatistics();
    }

    /**
     * 拒单
     *
     * @param dto dto
     */
    @Override
    public void rejectionOrder(OrdersRejectionDTO dto) {
        // 拒单,自动退款
        Orders orders = orderMapper.selectById(dto.getId());
        // 拒单原因
        orders.setRejectionReason(dto.getRejectionReason());
        // 订单状态 6已取消
        orders.setStatus(Orders.CANCELLED);
        // 支付状态 2退款
        orders.setPayStatus(Orders.REFUND);
        orderMapper.updateOrder(orders);
    }

    /**
     * 查询订单详情
     *
     * @param id 订单id
     * @return 订单详情数据
     */
    @Override
    public OrderVO selectOrderWithDetail(Long id) {
        return orderMapper.selectWithDetailById(id);
    }

    /**
     * 取消订单
     *
     * @param dto dto
     */
    @Override
    public void cancelOrderWithReason(OrdersCancelDTO dto) {
        Orders orders = orderMapper.selectById(dto.getId());
        // 取消原因
        orders.setCancelReason(dto.getCancelReason());
        // 订单状态 6已取消
        orders.setStatus(Orders.CANCELLED);
        // 支付状态 2退款
        orders.setPayStatus(Orders.REFUND);
        // 订单取消时间
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.updateOrder(orders);
    }

    /**
     * 接单
     *
     * @param dto dto
     */
    @Override
    public void confirmOrder(OrdersConfirmDTO dto) {
        Orders orders = orderMapper.selectById(dto.getId());
        // 订单状态 3已接单
        orders.setStatus(Orders.CONFIRMED);
        orderMapper.updateOrder(orders);
    }

    /**
     * 派送订单
     *
     * @param id 订单id
     */
    @Override
    public void deliveryOrder(Long id) {
        Orders orders = orderMapper.selectById(id);
        // 订单状态 4派送中
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        orderMapper.updateOrder(orders);
    }

    /**
     * 完成订单
     *
     * @param id 订单id
     */
    @Override
    public void completeOrder(Long id) {
        Orders orders = orderMapper.selectById(id);
        // 订单状态 5已完成
        orders.setStatus(Orders.COMPLETED);
        orderMapper.updateOrder(orders);
    }

    @Override
    public void reminderOrder(Long id) {
        Orders orders = orderMapper.selectById(id);

        // 通过WebSocket向管理端发信息
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", 2);
        jsonObject.put("orderId", id);
        jsonObject.put("content", "用户催单啦! 订单号:" + orders.getNumber());
        webSocketServer.sendToAllClient(jsonObject.toString());
    }


    /**
     * 营业额统计接口
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return vo
     */
    @Override
    public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
        // 先定义俩个集合(一个存放日期,一个存放营业额)
        List<String> dateList = new ArrayList<>();
        List<Double> turnoverList = new ArrayList<>();

        // 2.遍历日期,查询每天的营业额
        // while (!begin.isAfter(end))

        while (begin.isBefore(end.plusDays(1))) { // 开始日期在结束日期之后 取反 即 开始日期在结束日期之前
            // 查询当天的营业额

            // 获取当天的开始时间和结束时间
            LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(begin, LocalTime.MAX);

            // 构造查询条件
            Map<String, Object> map = new HashMap<>();
            map.put("begin", beginTime);
            map.put("end", endTime);
            map.put("status", Orders.COMPLETED);

            Double turnover = orderMapper.sumByMap(map);

            // 往俩个集合中添加数据
            dateList.add(begin.toString());
            turnoverList.add(turnover == null ? 0 : turnover);

            // 将当前日期加一天
            begin = begin.plusDays(1);
        }

        return TurnoverReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .turnoverList(StringUtils.join(turnoverList, ","))
                .build();
    }

    /**
     * 订单统计接口
     *
     * @param dto dto
     * @return vo
     */
    @Override
    public OrderReportVO getOrdersStatistics(DataOverViewQueryDTO dto) {
        // 1.定义仨集合
        List<String> dateList = new ArrayList<>(); // 日期
        List<Integer> orderCountList = new ArrayList<>(); // 每日订单数
        List<Integer> validOrderCountList = new ArrayList<>(); // 每日有效订单数

        LocalDate begin = dto.getBegin();
        LocalDate end = dto.getEnd();

        // 2. 遍历日期,得到每日的日期,订单数,有效订单数
        while (!begin.isAfter(end)) {
            LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN); //每天起始时间
            LocalDateTime endTime = LocalDateTime.of(begin, LocalTime.MAX); // 每天结束时间

            Map<String, Object> map = new HashMap<>();
            map.put("begin", beginTime);
            map.put("end", endTime);

            // 查询每日订单数
            Integer orderCount = orderMapper.countByMap(map);
            // 查询每日有效订单数
            map.put("status", Orders.COMPLETED);
            Integer validOrderCount = orderMapper.countByMap(map);

            dateList.add(begin.toString());
            validOrderCountList.add(validOrderCount);
            orderCountList.add(orderCount);

            begin = begin.plusDays(1);
        }

        // 3.返回数据
        // 计算订单总数,有效订单总数,订单完成率
        int total = orderCountList.stream().mapToInt(num -> num).sum();
        int valid = validOrderCountList.stream().mapToInt(num -> num).sum();
        Double orderCompletionRate = total == 0 ? 0 : (valid * 1.0 / total);

        return OrderReportVO.builder()
                .orderCompletionRate(orderCompletionRate)
                .totalOrderCount(total)
                .validOrderCount(valid)
                .orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ","))
                .dateList(StringUtils.join(dateList, ","))
                .build();
    }

    /**
     * 商品(菜品,套餐)销量排名前10统计
     *
     * @param dto dto
     * @return vo
     */
    @Override
    public SalesTop10ReportVO getTop10(DataOverViewQueryDTO dto) {
        LocalDate begin = dto.getBegin();
        LocalDate end = dto.getEnd();

        // 2 创建查询时间条件
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        // 3 查询销售前10的商品数据
        List<GoodsSalesDTO> list = orderMapper.getGoodNamesTop10(beginTime, endTime);
        String names = list.stream().map(n -> n.getName()).collect(Collectors.joining(","));
        String numbers = list.stream().map(n -> n.getNumber().toString()).collect(Collectors.joining(","));

        // 查询订单
        return SalesTop10ReportVO.builder()
                .nameList(names)
                .numberList(numbers)
                .build();

    }
}